using Devil;
using GameToolkit.BehaviourTree;
using System;
using UnityEditor.Experimental.GraphView;
using UnityEngine;

namespace GameToolkit.Editor
{
    using CompositeInfo = BehaviourTreeLib.CompositeInfo;

    //public partial class BehaviourTreeGraph
    //{
    internal class LogicNodeVisual : TreeGraphNode
    {
        internal static readonly Color INPUT_COLOR = new Color(0.5f, 0.5f, 0.0f);

        internal readonly Port inputPort;
        internal readonly Port successPort;
        internal readonly Port failedPort;
        public override bool IsDecoratorEditable => false;

        public LogicNodeVisual(CompositeInfo info, Composite asset) : base(info, asset)
        {
            successPort = InstantiatePort(Orientation.Horizontal, Direction.Output, Port.Capacity.Multi, typeof(NodeState));
            successPort.portName = "Execute";
            successPort.portColor = ExecutableNodeVisual.STAT_COLOR[2];
            outputContainer.Add(successPort);

            failedPort = InstantiatePort(Orientation.Horizontal, Direction.Output, Port.Capacity.Multi, typeof(NodeState));
            failedPort.portName = "Interrupt";
            failedPort.portColor = ExecutableNodeVisual.STAT_COLOR[3];
            outputContainer.Add(failedPort);
            if (composite is LogicWithInputComposite logic)
            {
                inputPort = InstantiatePort(Orientation.Horizontal, Direction.Input, logic.IsMultiInput ? Port.Capacity.Multi : Port.Capacity.Single, typeof(NodeState));
                inputPort.portColor = INPUT_COLOR;
                inputContainer.Add(inputPort);
            }
            Validate();
        }

        bool LogicCompositeFilter(SearchTreeEntry node)
        {
            if (node.userData is CompositeInfo cinfo)
                return (cinfo.NodeType == BehaviourTreeLib.EBTNodeType.ComplexLogic || cinfo.NodeType == BehaviourTreeLib.EBTNodeType.Condition);
            else
                return false;
        }

        public override Port InstantiatePort(Orientation orientation, Direction direction, Port.Capacity capacity, Type type)
        {
            var port = new GraphPort<LinkEdge>(orientation, direction, capacity, type);
            port.AutoCreationFilter = LogicCompositeFilter;
            return port;
            //return Port.Create<LinkEdge>(orientation, direction, capacity, type);
        }

        public override void SaveCompositeConnections(MinHeap<INodeWithComposite> nodeBuffer)
        {
            if (composite is LogicWithInputComposite logic)
            {
                // get inputs
                nodeBuffer.Clear();
                foreach (var edge in inputPort.connections)
                {
                    var input = edge.output.node as INodeWithComposite;
                    if (input != null)
                    {
                        input.temporaryPortId = input.GetOutputPortId(edge);
                        nodeBuffer.Add(input);
                    }
                }
                logic.inputs = BehaviourTreeGraphUtils.ToCompositesInput(nodeBuffer);
            }
        }

        public override void LoadCompositeConnections(BehaviourTreeGraph.GraphEdgeLoader edgeLoader)
        {
            if (composite is LogicWithInputComposite logic)
            {
                var inputs = logic.inputs;
                var len = inputs == null ? 0 : inputs.Length;
                for (int i = 0; i < len; i++)
                {
                    var node = edgeLoader.GetNode(inputs[i].composite);
                    if (node != null)
                    {
                        var port = node.GetOutputPort((int)inputs[i].state);
                        edgeLoader.NewEdge<LinkEdge>(inputPort, port);
                    }
                }
            }
        }

        public override bool IsCompatiblePort(Port port)
        {
            if (port.node is RegisterNodeVisual reg)
                return reg.composite is RegisterComposite;
            else
                return true;
        }

        public override void AutoConnectOnCreate(BehaviourTreeGraph graph, Port port)
        {
            if(port.node is ExecutableNodeVisual && port.direction == Direction.Input)
            {
                graph.DeleteElements(port.connections);
                port.DisconnectAll();
                graph.NewEdge<LinkEdge>(port, successPort);
            }
            else if(port.direction == Direction.Output)
            {
                graph.NewEdge<LinkEdge>(inputPort, port);
            }
            else
            {
                graph.NewEdge<LinkEdge>(port, successPort);
            }
        }

        public override void Validate()
        {
            base.Validate();
            if (composite is LogicWithInputComposite logic)
            {
                var portName = logic.InputPortName;
                if (string.IsNullOrEmpty(portName))
                    portName = logic.IsMultiInput ? "Input(s)" : "Input";
                inputPort.portName = portName;
            }
        }

        public override int GetInputPortId(Edge edge)
        {
            return 0;
        }

        public override Port GetInputPort(int id)
        {
            return inputPort;
        }

        public override Port GetOutputPort(int portId)
        {
            return portId == (int)NodeState.Success ? successPort : failedPort;
        }

        public override int GetOutputPortId(Edge edge)
        {
            return edge.output == successPort ? (int)NodeState.Success : (int)NodeState.Failed;
        }
    }
    //}
}
